<template>
  <div class="drawing-board-container">
    <!-- 上传图片 -->
    <input id="sketchpad-upload" ref="sketchpadUpload" type="file" accept="image/*" @change="uploadImg($event)">
    <!-- 工具列表 -->
    <div class="tool-container">
      <div class="tool-left">
        <el-dropdown>
          <span class="el-dropdown-link">
            <i class="el-icon-s-operation icon-operation" style="color: #737373;" />
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item @click.native="handleScreen">截屏</el-dropdown-item>
            <el-dropdown-item @click.native="changeTool('download')">下载</el-dropdown-item>
            <el-dropdown-item @click.native="changeTool('clear')">清空</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
      </div>
      <ul class="tool-box">
        <li class="tool-con">
          <el-color-picker v-model="strokeColor" />
        </li>
        <li class="tool-con">
          <el-input-number v-model="strokeWidth" controls-position="right" placeholder="线宽" :min="1" :max="20" />
        </li>
        <li v-for="item in tools" :key="item.type" class="tool-item" @click="changeTool(item.type)">
          <el-tooltip effect="dark" :content="item.name" placement="bottom">
            <label v-if="item.type === 'upload'" class="svg-icon" :class="{active: toolType === item.type}" for="sketchpad-upload" v-html="item.icon" />
            <div v-else-if="item.type==='undo'" class="svg-icon" :class="{active: toolType === item.type,disable:history.length===stage}" v-html="item.icon" />
            <div v-else-if="item.type==='redo'" class="svg-icon" :class="{active: toolType === item.type,disable:stage ===0}" v-html="item.icon" />
            <div v-else class="svg-icon" :class="{active: toolType === item.type}" v-html="item.icon" />
          </el-tooltip>
        </li>
      </ul>
      <div class="tool-right" />
    </div>

    <div id="drawing-board-wrap" ref="drawing-board-wrap" class="drawing-board-wrap">
      <!-- 画布 -->
      <canvas id="myCanvas" ref="myCanvas" />
    </div>
  </div>
</template>

<script>
import { fabric } from 'fabric'
import FileSaver from 'file-saver'
import { TOOLS, defaultProps } from './index'
import Kscreenshot from '@/components/kscreenshot/kss.js'

export default {
  props: defaultProps,
  data() {
    return {
      boardObj: null, // 存储当前画布对象
      mouseFrom: {}, // 鼠标按下的位置
      mouseTo: {}, // 鼠标抬起的位置
      toolType: 'pencil', // 当前工具类型
      isDrawing: false, // 是否正在画 鼠标按下和抬起的开关控制
      drawingObj: null, // 正在绘制的对象
      history: [], // 存放历史记录
      textObj: null, // 存储文字对象
      stage: 0,
      currImg: '',
      tools: TOOLS,
      strokeColor: '#000000', // 颜色
      strokeWidth: 2 // 线宽
    }
  },
  watch: {
    strokeColor(val) {
      this.boardObj.freeDrawingBrush.color = this.strokeColor
    },
    strokeWidth(val) {
      this.boardObj.freeDrawingBrush.width = this.strokeWidth * 1
    }
  },
  mounted() {
    this.boardObj = new fabric.Canvas('myCanvas', {
      isDrawingMode: true, // 是否可以自由绘制
      selectable: true, // 控件不能被选择
      selection: true, // 画板中是否显示选中
      devicePixelRatio: true
    })
    // fabric.Image.fromURL：加载图片的api
    // 第一个参数：图片地址（可以是本地的，也可以是网络图）
    // 第二个参数：图片加载的回调函数
    /* fabric.Image.fromURL(
      'http://localhost:9528/static/img/sub_logo.27855c23.png',
      (img) => {
        // 设置背景图
        this.boardObj.setBackgroundImage(
          img,
          this.boardObj.renderAll.bind(this.boardObj)
        )
      }
    )*/
    /**
     *  const imgObj = new Image()
        imgObj.src = base64图片
        imgObj.onload = () => {
          console.log('imgObj', imgObj)
          var oImg = new fabric.Image(imgObj)
          oImg.scale(0.5)
           this.boardObj.setBackgroundImage(
            oImg,
            this.boardObj.renderAll.bind(this.boardObj),
            {
              scaleX: this.boardObj.width / imgObj.width, // 计算出图片要拉伸的宽度
              scaleY: this.boardObj.height / imgObj.height // 计算出图片要拉伸的高度
            }
          )
        }
     */
    this.boardObj.freeDrawingBrush.color = this.strokeColor
    this.boardObj.freeDrawingBrush.width = this.strokeWidth * 1
    this.$nextTick(() => {
      this.boardObj.setWidth(this.$refs['drawing-board-wrap'].offsetWidth)
      this.boardObj.setHeight(this.$refs['drawing-board-wrap'].offsetHeight)
    })
    this.initEvent()
    this.kssInit()
  },
  methods: {
    kssInit() {
      const u = navigator.userAgent
      const isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios终端
      const textType = !isiOS
      this.kss = new Kscreenshot({
        toolShow: {
          text: textType
        },
        immediately: false,
        endCB: (base64) => {
          const imgObj = new Image()
          imgObj.src = base64
          imgObj.onload = () => {
            console.log('imgObj', imgObj)
            var oImg = new fabric.Image(imgObj)
            oImg.scale(0.5)
            this.boardObj.setBackgroundImage(
              oImg,
              this.boardObj.renderAll.bind(this.boardObj),
              {
                scaleX: this.boardObj.width / imgObj.width, // 计算出图片要拉伸的宽度
                scaleY: this.boardObj.height / imgObj.height // 计算出图片要拉伸的高度
              }
            )
          }
        },
        cancelCB: () => {
          console.log('取消了截屏')
        }
      })
    },
    initEvent() {
      this.boardObj.on({
        'mouse:down': (e) => {
          console.log('down', e)
          const { x, y } = e.pointer
          this.mouseFrom = { x, y }
          // 判断是否选中了对象
          if (!this.boardObj.getActiveObject()) {
            this.isDrawing = true
          }
          if (this.toolType === 'text') {
            this.drawText()
          }
        },
        'mouse:up': (e) => {
          console.log('up', e)
          const { x, y } = e.pointer
          this.mouseTo = { x, y }
          this.isDrawing = false
          this.drawingObj = null
          this.addHistory()
        },
        'mouse:move': e => {
          if (this.isDrawing) {
            console.log('move', e)
            const { x, y } = e.pointer
            this.mouseTo = { x, y }
            this.drawing()
          }
        },
        // 移动对象时触发该事件
        'object:moving': e => {
          console.log('移动', e)
        },
        // 放大或者缩小对象时触发该事件
        'object:scaling': e => {
          console.log('放大缩小', e)
        },
        // 旋转对象时触发该事件
        'object:rotating': e => {
          console.log('旋转', e)
        },
        'selection:created': e => {
          console.log('选中了')
          if (this.toolType === 'rubber') {
            console.log(e)
            if (e.selected) {
              // 多选删除
              var etCount = e.selected.length
              for (var i = 0; i < etCount; i++) {
                this.boardObj.remove(e.selected[i])
              }
            } else {
              // 单选删除
              this.boardObj.remove(e.target)
            }
            this.boardObj.discardActiveObject() // 清楚选中框
          }
          this.addHistory()
        }
      })
    },
    drawing() {
      // 判断是否是同一次绘制 是的话先清楚保留最后一次
      if (this.drawingObj) {
        this.boardObj.remove(this.drawingObj)
      }
      this.boardObj.isDrawingMode = false
      this.boardObj.selectable = false
      this.boardObj.selection = false
      let drawObj = null
      switch (this.toolType) {
        case 'pencil':
          this.boardObj.isDrawingMode = true
          break
        case 'line':
          drawObj = this.drawLine()
          break
        case 'dashedLine':
          drawObj = this.drawDashedLine()
          break
        case 'arrow':
          drawObj = this.drawArrow()
          break
        case 'rect':
          drawObj = this.drawRect()
          break
        case 'cricle':
          drawObj = this.drawCricle()
          break
        case 'ellipse':
          drawObj = this.drawEllipse()
          break
        case 'equilateral':
          drawObj = this.drawEquilateral()
          break
        default:
          drawObj = null
          this.boardObj.selection = true
          this.boardObj.skipTargetFind = false
          this.boardObj.selectable = true
          break
      }
      if (drawObj) {
        console.log(drawObj)
        this.boardObj.add(drawObj)
        this.drawingObj = drawObj
      }
    },
    // 选择工具
    changeTool(type) {
      this.boardObj.isDrawingMode = false
      this.resetDrawObj()
      // 如果有选中的对象先清除选中
      if (this.boardObj.getActiveObject()) {
        this.boardObj.discardActiveObject()
        this.boardObj.renderAll()
      }
      if (type === 'clear') {
        return this.boardObj.clear()
      }
      if (type === 'upload') {
        return
      }
      if (type === 'undo') {
        return this.undo()
      }
      if (type === 'redo') {
        return this.redo()
      }
      if (type === 'download') {
        return this.composeImg()
      }
      this.toolType = type
      if (type === 'pencil') {
        this.boardObj.isDrawingMode = true
      }
      if (type === 'rubber' || type === 'move') {
        this.boardObj.selection = true
        this.boardObj.skipTargetFind = false
        this.boardObj.selectable = true
      }
    },
    resetDrawObj() {
      this.boardObj.selectable = true
      this.boardObj.selection = true
      this.boardObj.skipTargetFind = false
      if (this.textObj) {
        this.textObj.exitEditing()
        this.textObj = null
      }
    },
    // 画实线
    drawLine() {
      return new fabric.Line([this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y], {
        stroke: this.strokeColor,
        strokeWidth: this.strokeWidth * 1
      })
    },
    // 画虚线
    drawDashedLine() {
      return new fabric.Line(
        [this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y],
        {
          stroke: this.strokeColor,
          strokeWidth: this.strokeWidth * 1,
          strokeDashArray: [10, 3]
        }
      )
    },
    // 画矩形
    drawRect() {
      return new fabric.Rect({
        left: this.mouseFrom.x,
        top: this.mouseFrom.y,
        height: Math.abs(this.mouseTo.y - this.mouseFrom.y),
        width: Math.abs(this.mouseTo.x - this.mouseFrom.x),
        stroke: this.strokeColor,
        strokeWidth: this.strokeWidth * 1,
        fill: 'rgba(255, 255, 255, 0)'
      })
    },
    // 画圆形
    drawCricle() {
      // 计算半径 勾股定理  a^2 + b^2 = c^2
      const a = this.mouseTo.x - this.mouseFrom.x
      const b = this.mouseTo.y - this.mouseFrom.y
      const r = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)) / 2
      return new fabric.Circle({
        left: this.mouseFrom.x,
        top: this.mouseFrom.y,
        stroke: this.strokeColor,
        fill: 'rgba(255, 255, 255, 0)',
        radius: r,
        strokeWidth: this.strokeWidth * 1
      })
    },
    // 画椭圆
    drawEllipse() {
      const left = this.mouseFrom.x
      const top = this.mouseFrom.y
      return new fabric.Ellipse({
        left: left,
        top: top,
        stroke: this.strokeColor,
        fill: 'rgba(255, 255, 255, 0)',
        originX: 'center',
        originY: 'center',
        rx: Math.abs(left - this.mouseTo.x),
        ry: Math.abs(top - this.mouseTo.y),
        strokeWidth: this.strokeWidth * 1
      })
    },
    // 画等边三角形
    drawEquilateral() {
      const height = this.mouseTo.y - this.mouseFrom.y
      return new fabric.Triangle({
        top: this.mouseFrom.y,
        left: this.mouseFrom.x,
        width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2, 2)),
        height: height,
        stroke: this.strokeColor,
        strokeWidth: this.strokeWidth * 1,
        fill: 'rgba(255,255,255,0)'
      })
    },
    // 画箭头
    drawArrow() {
      const [sx, sy] = [this.mouseFrom.x, this.mouseFrom.y]
      const [ex, ey] = [this.mouseTo.x, this.mouseTo.y]
      const disY = sy - ey
      const disX = sx - ex
      const theta = 30
      const headlen = 30
      var angle = Math.atan2(disY, disX) * 180 / Math.PI
      var angle1 = (angle + theta) * Math.PI / 180
      var angle2 = (angle - theta) * Math.PI / 180
      var topX = headlen * Math.cos(angle1)
      var topY = headlen * Math.sin(angle1)
      var botX = headlen * Math.cos(angle2)
      var botY = headlen * Math.sin(angle2)
      var arrowX = sx - topX
      var arrowY = sy - topY
      var path = ' M ' + sx + ' ' + sy
      path += ' L ' + ex + ' ' + ey
      arrowX = ex + topX
      arrowY = ey + topY
      path += ' M ' + arrowX + ' ' + arrowY
      path += ' L ' + ex + ' ' + ey
      arrowX = ex + botX
      arrowY = ey + botY
      path += ' L ' + arrowX + ' ' + arrowY
      return new fabric.Path(path, {
        stroke: this.strokeColor,
        fill: 'rgba(255,255,255,0)',
        strokeWidth: this.strokeWidth * 1
      })
    },
    drawText() {
      const { x, y } = this.mouseFrom
      this.textObj = new fabric.Textbox('', {
        left: x,
        top: y,
        width: '',
        height: '',
        fill: this.strokeColor,
        hasControls: true
      })
      this.boardObj.add(this.textObj)
      this.textObj.enterEditing()
      this.textObj.hiddenTextarea.focus()
      this.addHistory()
    },
    // 增加历史记录
    addHistory() {
      this.history.push(JSON.stringify(this.boardObj))
    },
    // 撤消
    undo() {
      const stack = this.history
      if (this.stage < stack.length) {
        this.boardObj.clear().renderAll()
        this.boardObj.loadFromJSON(stack[stack.length - 1 - this.stage - 1])
        this.boardObj.renderAll()
        this.stage += 1
      }
    },
    // 前进
    redo() {
      const stack = this.history
      if (this.stage > 0) {
        this.boardObj.clear().renderAll()
        this.boardObj.loadFromJSON(stack[stack.length - 1 - this.stage + 1])
        this.boardObj.renderAll()
        this.stage -= 1
      }
    },
    // 合成图片并下载
    composeImg() {
      const base64Img = this.boardObj.toDataURL({
        formart: 'png',
        multiplier: 2
      })
      const bd = base64Img.split(',')
      const mime = bd[0].match(/:(.*?);/)[1]
      const bstr = atob(bd[1]); let l = bstr.length; const u8arr = new Uint8Array(l)
      while (l--) {
        u8arr[l] = bstr.charCodeAt(l)
      }
      const blobData = new Blob([u8arr], { type: mime })
      console.log('blob', blobData)
      FileSaver.saveAs(blobData, 'sketchpad.png')
    },
    uploadImg(e) {
      const imgData = e.target.files[0]
      const reader = new FileReader()
      reader.onload = res => {
        const dataUrl = res.target.result
        const imgObj = new Image()
        imgObj.src = dataUrl
        imgObj.onload = () => {
          console.log('imgObj', imgObj)
          var oImg = new fabric.Image(imgObj)
          oImg.scale(0.5)
          this.boardObj.centerObject(oImg).add(oImg).renderAll()
          // 为了连续两次选择同一张图片不触发onchange事件
          this.$refs.sketchpadUpload.value = ''
        }
      }
      reader.readAsDataURL(imgData)
    },
    handleScreen() {
      this.$nextTick(() => {
        this.kss.startScreenShot()
      })
    }
  }
}
</script>
<style lang="scss">
  .drawing-board-container{
    background-color: #f1f3f4;
    min-width: 600px;
    min-height: 600px;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    #sketchpad-upload {
      display: none;
    }
    .tool-container{
      height: 53px;
      width: 100%;
      background: #f1f3f4;
      border: 1px solid #dadce0;
      display: flex;
      flex-direction: row;
      justify-content: space-between;
      .tool-left{
        line-height: 58px;
        .icon-operation{
          font-size: 24px;
          margin-left: 14px;
          cursor: pointer;
        }
      }
      .tool-box {
        display: flex;
        flex-direction: row;
        .tool-con{
          display: flex;
          flex-direction: column;
          justify-content: center;
          margin-left: 4px;
        }
        .tool-item {
          width: 50px;
          height: 50px;
          font-size:12px;
          cursor: pointer;
          .svg-icon{
            display: flex;
            flex-direction: column;
            justify-content: center;
            width: 100%;
            height: 100%;
            svg{
              width: 36px;
              height: 36px;
              border-radius: 4px;
              fill: #737373;
              stroke: #737373;
            }
            &.active {
              svg{
                stroke: #4a5dff;
                fill: #4a5dff;
                background: #fff;
              }
            }
            &.disable{
              svg{
                stroke: #C0C0C0;
                fill: #C0C0C0;
                cursor: not-allowed;
                border: none;
              }
            }
          }
        }
      }
    }
    .drawing-board-wrap{
      flex: 1;
      background: url() repeat !important;
      #myCanvas {
        width: 100%;
        height: 100%;
      }
    }
  }
</style>

